﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Diagnostics;
using System.Threading.Tasks;

namespace iTunesPlaycountUpdater
{
    class LastFmEnumerable : IEnumerable<LastFmTrack>
    {
        private string apiKey;
        private string userName;

        public LastFmEnumerable(string apiKey, string userName)
        {
            this.apiKey = apiKey;
            this.userName = userName;
        }

        public IEnumerator<LastFmTrack> GetEnumerator()
        {
            return new LastFmEnumerator(apiKey, userName);
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        private sealed class LastFmEnumerator : IEnumerator<LastFmTrack>
        {
            private bool disposed = false;
            private readonly string apiKey;
            private readonly string userName;

            private List<LastFmTrack> items = new List<LastFmTrack>();
            private int currentIndex = -1;
            bool downloadingFinished;

            public LastFmTrack Current
            {
                get
                {
                    if (disposed)
                        throw new ObjectDisposedException("LastFmEnumerator");

                    while (!downloadingFinished && currentIndex >= items.Count)
                        if (!downloadingFinished)
                            System.Threading.Thread.Sleep(50);
                        else
                            currentIndex--;
                    return this.items[currentIndex];
                }
                private set
                {

                }
            }

            public LastFmEnumerator(string apiKey, string user)
            {
                this.apiKey = apiKey;
                this.userName = user;

                Task.Factory.StartNew(DownloadItems);
            }

            public bool MoveNext()
            {
                if (disposed)
                    throw new ObjectDisposedException("LastFmEnumerator");

                if (++currentIndex >= items.Count)
                {
                    if (downloadingFinished)
                    {
                        currentIndex--;
                        return false;
                    }
                }
                return true;
            }

            private void DownloadItems()//int a)
            {
                downloadingFinished = false;

                //using (WebClient client = new WebClient())

                int totalPages;
                this.items.AddRange(LastFmApiResponseParser.ParseGetTracksResponse(LastFmApi.GetTracks(apiKey, userName, 1, out totalPages)));

                Parallel.For(2, totalPages, i =>
                //for (int i = 2; i < totalPages; i++)
                {
                    var downloadedItems = LastFmApi.GetTracks(apiKey, userName, i);

                    var parsedItems = LastFmApiResponseParser.ParseGetTracksResponse(downloadedItems);
                    this.items.AddRange(parsedItems);
                    Debug.WriteLine("Page {0} downloaded!", i);
                });


                downloadingFinished = true;
                Debug.WriteLine("Downloading finished!");


                Parallel.For(2, totalPages,
                    () =>
                        {
                            return new WebClient();
                        },
                    (i, loopstate, client) =>
                        {
                            return client;
                        },
                    (client) =>
                        {
                            client.Dispose();
                        });

            }

            public void Reset()
            {
                if (disposed)
                    throw new ObjectDisposedException("LastFmEnumerable");

                currentIndex = 0;
            }

            public void Dispose()
            {
                Dispose(true);
            }
            private void Dispose(bool disposing)
            {
                if (!disposed)
                {
                    if (disposing)
                    {
                        items = null;
                    }
                }
            }

            object System.Collections.IEnumerator.Current
            {
                get { return Current; }
            }
        }
    }
}
